#pragma once

#include "myapp.h"
#include "mydatamodel.h"

#include "wx/artprov.h"
#include "wx/dataview.h"
#include "wx/datetime.h"
#include "wx/splitter.h"
#include "wx/aboutdlg.h"
#include "wx/colordlg.h"
#include "wx/choicdlg.h"
#include "wx/numdlg.h"
#include "wx/spinctrl.h"
#include "wx/imaglist.h"
#include "wx/itemattr.h"
#include "wx/notebook.h"
#include "wx/popupwin.h"

#ifdef wxHAS_GENERIC_DATAVIEWCTRL
    #include "wx/headerctrl.h"
#endif // wxHAS_GENERIC_DATAVIEWCTRL

void SetHeaderCustomDraw(wxHeaderCtrl *header, std::function<void(wxDC &dc, const wxRect& rect)> cb);

class MyScrollBar : public wxScrollBar
	, public zqdb::SkinMap<MyScrollBar, SkinInfo>
{
	typedef wxScrollBar Base;
	typedef zqdb::SkinMap<MyScrollBar, SkinInfo> SkinBase;
private:
	wxScrollHelper* target_ = nullptr;
	wxScrollbarVisibility visibility_ = wxSHOW_SB_DEFAULT;
	int thumb_pos_ = 0;
	int thumb_size_ = 0;
	int page_size_ = 0;
	int range_ = 0;
	double ratio_ = 0;
	wxRect rc_thumb_;
	int track_ = 0;
	void Calc();
	void Scroll(int position);
public:
	using Base::Base;

	void SetScrollTarget(wxScrollHelper* target);
	void SetVisibility(wxScrollbarVisibility visibility);

	void OnSkinInfoChanged();
	bool IsCustomDraw() const;

	// accessors
	int GetThumbPosition() const;
	int GetThumbSize() const;
	int GetPageSize() const;
	int GetRange() const;

	bool IsVertical() const;

	// operations
	void SetThumbPosition(int viewStart);
	void SetScrollbar(int position, int thumbSize,
		int range, int pageSize,
		bool refresh = true);

protected:
	void OnErase(wxEraseEvent &event);
	void OnPaint(wxPaintEvent &event);
	void OnMouse(wxMouseEvent &event);
	void OnMouseLost(wxMouseCaptureLostEvent& event);
	void OnScroll(wxScrollEvent &event);

	wxDECLARE_EVENT_TABLE();
};

///

template<class TBase>
class MyScrollT : public TBase
{
	typedef MyScrollT<TBase> This;
	typedef TBase Base;
public:
	/*WNDPROC old_wndproc_ = nullptr;
	static LRESULT CALLBACK MyWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		auto pThis = (This*)GetProp(hwnd, _T("MyScrollBar"));
		switch (uMsg)
		{
		case WM_NCCALCSIZE: {
#if 1
			::ShowScrollBar(hwnd, SB_BOTH, FALSE);
#else
			BOOL bCalcValidRects = (BOOL)wParam;
			NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)lParam;

			DWORD     dwStyle;
			RECT*     lprc;

			lprc = &lpncsp->rgrc[0];
			dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);

			if ((dwStyle & WS_HSCROLL)) {
				int sz = ::GetSystemMetrics(SM_CYVSCROLL);
				lprc->bottom += sz;
			}

			if ((dwStyle & WS_VSCROLL)) {
				int sz = ::GetSystemMetrics(SM_CXVSCROLL);
				lprc->right += sz;
			}
#endif
		} break;
		}
		return CallWindowProc(pThis->old_wndproc_, hwnd, uMsg, wParam, lParam);
	}*/
protected:
	MyScrollBar* hscrollbar_ = nullptr;
	MyScrollBar* vscrollbar_ = nullptr;
	void UpdateScrollBar()
	{
		if (hscrollbar_) {
			::ShowScrollBar(GetHandle(), SB_HORZ, FALSE);
			int position = GetScrollPos(wxSB_HORIZONTAL);
			int thumbSize = GetScrollThumb(wxSB_HORIZONTAL);
			int range = GetScrollRange(wxSB_HORIZONTAL);
			int pageSize = GetScrollPageSize(wxSB_HORIZONTAL);
			hscrollbar_->SetScrollbar(position
				, thumbSize
				, range
				, pageSize);
		}
		if (vscrollbar_) {
			::ShowScrollBar(GetHandle(), SB_VERT, FALSE);
			int position = GetScrollPos(wxSB_VERTICAL);
			int thumbSize = GetScrollThumb(wxSB_VERTICAL);
			int range = GetScrollRange(wxSB_VERTICAL);
			int pageSize = GetScrollPageSize(wxSB_VERTICAL);
			vscrollbar_->SetScrollbar(position
				, thumbSize
				, range
				, pageSize);
		}
	}
public:
	using Base::Base;

	void SetScrollBar(MyScrollBar* hscrollbar, MyScrollBar* vscrollbar)
	{
		hscrollbar_ = hscrollbar;
		if (hscrollbar_)
			hscrollbar_->SetScrollTarget(this);
		vscrollbar_ = vscrollbar;
		if (vscrollbar_)
			vscrollbar_->SetScrollTarget(this);
		auto scroll_func = [this](wxScrollWinEvent &event) {
			event.Skip();
			UpdateScrollBar();
		};
		Bind(wxEVT_SCROLLWIN_TOP, scroll_func);
		Bind(wxEVT_SCROLLWIN_BOTTOM, scroll_func);
		Bind(wxEVT_SCROLLWIN_LINEUP, scroll_func);
		Bind(wxEVT_SCROLLWIN_LINEDOWN, scroll_func);
		Bind(wxEVT_SCROLLWIN_PAGEUP, scroll_func);
		Bind(wxEVT_SCROLLWIN_PAGEDOWN, scroll_func);
		Bind(wxEVT_SCROLLWIN_THUMBTRACK, scroll_func);
		Bind(wxEVT_SCROLLWIN_THUMBRELEASE, scroll_func);
		//HWND hwnd = GetHandle();
		//::SetProp(hwnd, _T("MyScrollBar"), (HANDLE)this);
		//old_wndproc_ = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
	}
	
	virtual void AdjustScrollbars() wxOVERRIDE
	{
		Base::AdjustScrollbars();
		UpdateScrollBar();
	}

protected:

	virtual void DoShowScrollbars(wxScrollbarVisibility horz,
		wxScrollbarVisibility vert) wxOVERRIDE
	{
		Base::DoShowScrollbars(horz, vert);
		if (hscrollbar_)
			hscrollbar_->SetVisibility(horz);
		if (vscrollbar_)
			vscrollbar_->SetVisibility(vert);
	}
};

// ----------------------------------------------------------------------------
// MyCustomRenderer
// ----------------------------------------------------------------------------

class MyCustomRenderer: public wxDataViewCustomRenderer
{
public:
    // This renderer can be either activatable or editable, for demonstration
    // purposes. In real programs, you should select whether the user should be
    // able to activate or edit the cell and it doesn't make sense to switch
    // between the two -- but this is just an example, so it doesn't stop us.
    explicit MyCustomRenderer(wxDataViewCellMode mode)
        : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
       { }

    virtual bool Render( wxRect rect, wxDC *dc, int state ) wxOVERRIDE
    {
        dc->SetBrush( *wxLIGHT_GREY_BRUSH );
        dc->SetPen( *wxTRANSPARENT_PEN );

        rect.Deflate(2);
        dc->DrawRoundedRectangle( rect, 5 );

        RenderText(m_value,
                   0, // no offset
                   wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
                   dc,
                   state);
        return true;
    }

    virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
                              wxDataViewModel *WXUNUSED(model),
                              const wxDataViewItem &WXUNUSED(item),
                              unsigned int WXUNUSED(col),
                              const wxMouseEvent *mouseEvent) wxOVERRIDE
    {
        wxString position;
        if ( mouseEvent )
            position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
        else
            position = "from keyboard";
        wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
        return false;
    }

    virtual wxSize GetSize() const wxOVERRIDE
    {
        return wxSize(60,20);
    }

    virtual bool SetValue( const wxVariant &value ) wxOVERRIDE
    {
        m_value = value.GetString();
        return true;
    }

    virtual bool GetValue( wxVariant &WXUNUSED(value) ) const wxOVERRIDE { return true; }

#if wxUSE_ACCESSIBILITY
    virtual wxString GetAccessibleDescription() const wxOVERRIDE
    {
        return m_value;
    }
#endif // wxUSE_ACCESSIBILITY

    virtual bool HasEditorCtrl() const wxOVERRIDE { return true; }

    virtual wxWindow*
    CreateEditorCtrl(wxWindow* parent,
                     wxRect labelRect,
                     const wxVariant& value) wxOVERRIDE
    {
        wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
                                          labelRect.GetPosition(),
                                          labelRect.GetSize(),
                                          wxTE_PROCESS_ENTER);
        text->SetInsertionPointEnd();

        return text;
    }

    virtual bool
    GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) wxOVERRIDE
    {
        wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
        if ( !text )
            return false;

        value = text->GetValue();

        return true;
    }

private:
    wxString m_value;
};


// ----------------------------------------------------------------------------
// MultiLineCustomRenderer
// ----------------------------------------------------------------------------

class MultiLineCustomRenderer : public wxDataViewCustomRenderer
{
public:
    // a simple renderer that wraps each word on a new line
    explicit MultiLineCustomRenderer()
        : wxDataViewCustomRenderer("string", wxDATAVIEW_CELL_INERT, 0)
    { }

    virtual bool Render(wxRect rect, wxDC *dc, int state) wxOVERRIDE
    {
        RenderText(m_value, 0, rect, dc, state);
        return true;
    }

    virtual wxSize GetSize() const wxOVERRIDE
    {
        wxSize txtSize = GetTextExtent(m_value);
        int lines = m_value.Freq('\n') + 1;
        txtSize.SetHeight(txtSize.GetHeight() * lines);
        return txtSize;
    }

    virtual bool SetValue(const wxVariant &value) wxOVERRIDE
    {
        m_value = value.GetString();
        m_value.Replace(" ", "\n");
        return true;
    }

    virtual bool GetValue(wxVariant &WXUNUSED(value)) const wxOVERRIDE { return true; }

#if wxUSE_ACCESSIBILITY
    virtual wxString GetAccessibleDescription() const wxOVERRIDE
    {
        return m_value;
    }
#endif // wxUSE_ACCESSIBILITY

private:
    wxString m_value;
};


// ----------------------------------------------------------------------------
// SmartKBListCustomRenderer
// ----------------------------------------------------------------------------

class SmartKBListRenderer : public wxDataViewCustomRenderer
{
public:
	using wxDataViewCustomRenderer::wxDataViewCustomRenderer;

	virtual bool Render(wxRect rect, wxDC *dc, int state) wxOVERRIDE
	{
		//dc->DrawText(m_value, rect.GetLeftTop());
		//RenderText(m_value, 0, rect, dc, state);
		return true;
	}

	virtual wxSize GetSize() const wxOVERRIDE
	{
		return GetTextExtent(m_value);
	}

	virtual bool SetValue(const wxVariant &value) wxOVERRIDE
	{
		m_value = value.GetString();
		return true;
	}

	virtual bool GetValue(wxVariant &WXUNUSED(value)) const wxOVERRIDE { return true; }

#if wxUSE_ACCESSIBILITY
	virtual wxString GetAccessibleDescription() const wxOVERRIDE
	{
		return m_value;
	}
#endif // wxUSE_ACCESSIBILITY

private:
	wxString m_value;
};

// ----------------------------------------------------------------------------
// MyCodeViewListRenderer
// ----------------------------------------------------------------------------

class MyCodeView;
class MyCodeViewListRenderer : public wxDataViewCustomRenderer
	, public zqdb::SkinMap<MyCodeViewListRenderer, SkinInfo>
{
public:
	// a simple renderer that wraps each word on a new line
	explicit MyCodeViewListRenderer();
	explicit MyCodeViewListRenderer(MyCodeView* view);

	void OnSkinInfoChanged();

	virtual void RenderBackground(wxDC* dc, const wxRect& rect) wxOVERRIDE;

	virtual bool Render(wxRect rect, wxDC *dc, int state) wxOVERRIDE;

	virtual wxSize GetSize() const wxOVERRIDE;

	virtual bool SetValue(const wxVariant &value) wxOVERRIDE;

	virtual bool GetValue(wxVariant &WXUNUSED(value)) const wxOVERRIDE;

#if wxUSE_ACCESSIBILITY
	virtual wxString GetAccessibleDescription() const wxOVERRIDE;
#endif // wxUSE_ACCESSIBILITY

private:
	MyCodeView* view_;
	SmartKBItem* val_ = nullptr;
	wxFont fontName_;
	wxFont fontCode_;
	wxFont fontPrice_;
	wxColour crName_;
	wxColour crCode_;
};

// ----------------------------------------------------------------------------
// MyCodeListCodeRenderer
// ----------------------------------------------------------------------------

class MyCodeListCodeRenderer : public wxDataViewCustomRenderer
	, public zqdb::SkinMap<MyCodeListCodeRenderer, SkinInfo>
{
public:
	// a simple renderer that wraps each word on a new line
	explicit MyCodeListCodeRenderer();

	virtual bool Render(wxRect rect, wxDC *dc, int state) wxOVERRIDE;

	virtual wxSize GetSize() const wxOVERRIDE;

	virtual bool SetValue(const wxVariant &value) wxOVERRIDE;

	virtual bool GetValue(wxVariant &WXUNUSED(value)) const wxOVERRIDE;

#if wxUSE_ACCESSIBILITY
	virtual wxString GetAccessibleDescription() const wxOVERRIDE;
#endif // wxUSE_ACCESSIBILITY

private:
	HZQDB h_ = nullptr;
	wxString name_;
	wxString code_;
};


// ----------------------------------------------------------------------------
// MyCodeListNameRenderer
// ----------------------------------------------------------------------------

class MyCodeListNameRenderer : public wxDataViewCustomRenderer
	, public zqdb::SkinMap<MyCodeListNameRenderer, SkinInfo>
{
public:
	// a simple renderer that wraps each word on a new line
	explicit MyCodeListNameRenderer();

	virtual bool Render(wxRect rect, wxDC *dc, int state) wxOVERRIDE;

	virtual wxSize GetSize() const wxOVERRIDE;

	virtual bool SetValue(const wxVariant &value) wxOVERRIDE;

	virtual bool GetValue(wxVariant &WXUNUSED(value)) const wxOVERRIDE;

#if wxUSE_ACCESSIBILITY
	virtual wxString GetAccessibleDescription() const wxOVERRIDE;
#endif // wxUSE_ACCESSIBILITY

private:
	HZQDB h_ = nullptr;
	CODEINFO* info_ = nullptr;
};

